package com.framework.websocket.endpoint;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.framework.websocket.core.GenericMessageHandler;
import com.framework.websocket.core.SubscriptionConfig;
import com.framework.websocket.core.WebSocketManager;
import com.framework.websocket.model.CommandType;
import com.framework.websocket.model.SubscribeMessage;
import com.framework.websocket.service.HeartbeatManager;
import com.framework.websocket.utils.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.HashMap;

/**
 * WebSocket 端点
 * 处理所有 WebSocket 连接和消息
 */
@Slf4j
@Component
@ServerEndpoint("/ws")
public class WebSocketEndpoint {
    
    private static final ObjectMapper objectMapper = new ObjectMapper();
    
    // 使用静态方法获取 Spring Bean
    private static WebSocketManager getWebSocketManager() {
        return SpringContextUtils.getBean(WebSocketManager.class);
    }
    
    private static GenericMessageHandler getMessageHandler() {
        return SpringContextUtils.getBean(GenericMessageHandler.class);
    }
    
    private static HeartbeatManager getHeartbeatManager() {
        return SpringContextUtils.getBean(HeartbeatManager.class);
    }
    
    private static SubscriptionConfig getSubscriptionConfig() {
        return SpringContextUtils.getBean(SubscriptionConfig.class);
    }
    
    @OnOpen
    public void onOpen(Session session) {
        try {
            // 添加会话
            String clientId = getWebSocketManager().addSession(session);
            
            // 发送欢迎消息
            Map<String, Object> connectedResponse = new HashMap<>();
            connectedResponse.put("clientId", clientId);
            connectedResponse.put("message", "连接成功");
            getWebSocketManager().sendMessage(session, "CONNECTED", null, connectedResponse);
            
            // 记录心跳
            getHeartbeatManager().recordHeartbeat(session);
            
        } catch (Exception e) {
            log.error("WebSocket 连接建立失败", e);
            closeSession(session);
        }
    }
    
    @OnMessage
    public void onMessage(String message, Session session) {
        try {
            // 解析消息
            SubscribeMessage subscribeMessage = objectMapper.readValue(message, SubscribeMessage.class);
            String command = subscribeMessage.getCommand();
            String topic = subscribeMessage.getTopic();
            String params = subscribeMessage.getParams() != null ? 
                subscribeMessage.getParams().toString() : null;
            
            log.debug("收到消息 - SessionId: {}, Command: {}, Topic: {}, Params: {}", 
                session.getId(), command, topic, params);
            
            // 处理命令
            handleCommand(session, command, topic != null ? topic : params);
            
        } catch (Exception e) {
            log.error("处理消息失败 - SessionId: {}, Message: {}", session.getId(), message, e);
            getWebSocketManager().sendError(session, "消息格式错误");
        }
    }
    
    @OnClose
    public void onClose(Session session) {
        try {
            // 清除订阅
            getMessageHandler().clearSubscriptions(session);
            
            // 移除心跳记录
            getHeartbeatManager().removeHeartbeat(session);
            
            // 移除会话
            getWebSocketManager().removeSession(session);
            
        } catch (Exception e) {
            log.error("WebSocket 连接关闭处理失败", e);
        }
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("WebSocket 错误 - SessionId: {}", session.getId(), error);
        closeSession(session);
    }
    
    /**
     * 处理客户端命令
     */
    private void handleCommand(Session session, String command, String params) {
        CommandType commandType;
        try {
            commandType = CommandType.valueOf(command.toUpperCase());
        } catch (IllegalArgumentException e) {
            log.warn("未知命令: {}", command);
            getWebSocketManager().sendError(session, "未知命令: " + command);
            return;
        }
        
        switch (commandType) {
            case HEARTBEAT:
                // 处理心跳
                getHeartbeatManager().handleHeartbeat(session);
                Map<String, Object> heartbeatResponse = new HashMap<>();
                heartbeatResponse.put("timestamp", System.currentTimeMillis());
                getWebSocketManager().sendMessage(session, "HEARTBEAT_ACK", null, heartbeatResponse);
                break;
                
            case SUBSCRIBE:
                // 订阅
                if (params == null || params.isEmpty()) {
                    getWebSocketManager().sendError(session, "订阅类型不能为空");
                    return;
                }
                getMessageHandler().subscribe(session, params);
                break;
                
            case UNSUBSCRIBE:
                // 取消订阅
                if (params == null || params.isEmpty()) {
                    getWebSocketManager().sendError(session, "取消订阅类型不能为空");
                    return;
                }
                getMessageHandler().unsubscribe(session, params);
                Map<String, Object> unsubscribeResponse = new HashMap<>();
                unsubscribeResponse.put("message", "取消订阅成功");
                getWebSocketManager().sendMessage(session, "UNSUBSCRIBED", params, unsubscribeResponse);
                break;
                
            case CLEAR:
                // 清除所有订阅
                getMessageHandler().clearSubscriptions(session);
                Map<String, Object> clearResponse = new HashMap<>();
                clearResponse.put("message", "已清除所有订阅");
                getWebSocketManager().sendMessage(session, "CLEARED", null, clearResponse);
                break;
                
            case LIST:
                // 列出所有可用的订阅类型
                Map<String, String> types = getSubscriptionConfig().getTypeDescriptions();
                getWebSocketManager().sendMessage(session, "SUBSCRIPTION_TYPES", null, types);
                break;
                
            case STATUS:
                // 获取连接状态
                Map<String, Object> status = new HashMap<>();
                status.put("connected", true);
                status.put("sessionId", session.getId());
                status.put("clientId", getWebSocketManager().getClientId(session.getId()));
                status.put("subscriptions", getMessageHandler().getSubscriptionStats());
                getWebSocketManager().sendMessage(session, "STATUS", null, status);
                break;
                
            default:
                getWebSocketManager().sendError(session, "不支持的命令: " + command);
        }
    }
    
    /**
     * 关闭会话
     */
    private void closeSession(Session session) {
        if (session.isOpen()) {
            try {
                session.close();
            } catch (IOException e) {
                log.error("关闭会话失败", e);
            }
        }
    }
}